package org.springframework.beans.factory.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.StringValueResolver;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author derekyi
 * @date 2020/11/22
 */

//AbstractBeanFactory也是继承了DefaultSingletonBeanRegistry（默认单例bean工厂，他实现的是对单例bean的操作）
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
	//也就是前后置方法的类对象，我们之前手动加进去。这里后面会遍历，执行前后置方法
	//保存所有的beanPostProcessors，那他是什么时候保存的beanPostProcessors，看看源码
	private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

	//这个是存factoryBean的map集合
	private final Map<String, Object> factoryBeanObjectCache = new HashMap<>();

	private final List<StringValueResolver> embeddedValueResolvers = new ArrayList<StringValueResolver>();
	//类型转换器，给bean填充属性的时候，value值进行类型转换为原本的类型
	private ConversionService conversionService;


	@Override
	public Object getBean(String name) throws BeansException {
		//getSingleton方法，就是去123级缓存去找
		//如果bean是单例，在第一次创建bean实例后会存入1级缓存，（123级缓存），就会直接返回看看能不能返回
		//如果不是单例就不会进入1集缓存的map集合
		Object sharedInstance = getSingleton(name);
		if (sharedInstance != null) {
			//说明在123级缓存里有
			//如果是FactoryBean，从FactoryBean#getObject中创建bean。一级缓存里一般有FactoryBean的实例化bean
			return getObjectForBeanInstance(sharedInstance, name);
		}


		//都为空说明之前没有，就需要实例化了，先包装，之前注册过helloserviceDefinition了，
		// 我们从map中取到他对应的beanDefinition
		// （getBeanDefinition这里是他的实现类的ioc容器的方法）
		BeanDefinition beanDefinition = getBeanDefinition(name);

		//用这个beanDefinition名称和name得到一个bean（Object类型的），接下来就可以实例化bean了
		Object bean = createBean(name, beanDefinition);
		//这里面先进行实例化


		//我们需要知道类型转换器也是FactoryBean，所以会走这里
		//FactoryBean
		//需要看这里，存入已经被实例化好并填充属性的bean，
		return getObjectForBeanInstance(bean, name);
	}

	/**
	 * 如果是FactoryBean，从FactoryBean#getObject中创建bean
	 *
	 * @param beanInstance
	 * @param beanName
	 * @return
	 */
	protected Object getObjectForBeanInstance(Object beanInstance, String beanName) {

		Object object = beanInstance;
		//这里判断这个bean是否实现了FactoryBean接口
		if (beanInstance instanceof FactoryBean) {
			FactoryBean factoryBean = (FactoryBean) beanInstance;//先强转
			try {
				//是否是单例
				if (factoryBean.isSingleton()) {
					//FactoryBean也有一个对应的集合，存实例化对象，一级缓存里存的是没有被覆盖的对象
					object = this.factoryBeanObjectCache.get(beanName);
					//这是一个map集合类，尝试取这个bean，大概率第一次没有
					if (object == null) {//这里没有
						object = factoryBean.getObject();//直接调用我们之前定义好的方法
						this.factoryBeanObjectCache.put(beanName, object);//如果bean是单例的，我们这里会做一个缓存，之后来取
					}
				} else {
					//在这里prototype作用域bean，新创建bean
					object = factoryBean.getObject();//我们看看类型转换器里的getObject
				}
			} catch (Exception ex) {
				throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", ex);
			}
		}

		return object;
	}

	@Override
	public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
		return ((T) getBean(name));
	}

	@Override
	public boolean containsBean(String name) {
		return containsBeanDefinition(name);
	}

	protected abstract boolean containsBeanDefinition(String beanName);

	protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;

	protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

	@Override
	public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
		//有则覆盖，如果原来有了前后置方法对象，就覆盖了
		this.beanPostProcessors.remove(beanPostProcessor);
		this.beanPostProcessors.add(beanPostProcessor);
	}

	public List<BeanPostProcessor> getBeanPostProcessors() {
		return this.beanPostProcessors;
	}

	public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
		this.embeddedValueResolvers.add(valueResolver);
	}

	public String resolveEmbeddedValue(String value) {
		String result = value;

		for (StringValueResolver resolver : this.embeddedValueResolvers) {
			//这个里面的方法和之前配置类一样，对属性占位符切割。去配置文件找值，传回来
			result = resolver.resolveStringValue(result);
		}
		return result;
	}
	//类型转换也在AbstractBeanFactory
	@Override
	public ConversionService getConversionService() {
		return conversionService;
	}

	@Override
	public void setConversionService(ConversionService conversionService) {
		this.conversionService = conversionService;
	}
}
